package com.jianzong.lingxuan.api.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.jianzong.lingxuan.api.entity.SectCharacter;
import com.jianzong.lingxuan.api.entity.SectGongfa;
import com.jianzong.lingxuan.api.entity.SectGongfaRecord;
import com.jianzong.lingxuan.api.entity.SectUser;
import com.jianzong.lingxuan.api.entity.vo.UserGame;
import com.jianzong.lingxuan.api.mapper.SectCharacterMapper;
import com.jianzong.lingxuan.api.mapper.SectGongfaMapper;
import com.jianzong.lingxuan.api.mapper.SectGongfaRecordMapper;
import com.jianzong.lingxuan.api.service.GameService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @auth Leiwenlong
 * @since 2021/7/28
 */
@Service
public class GameServiceImpl implements GameService {

    private SectCharacter sectCharacter;

    private SectCharacter sectCharacterOneRecord;

    private SectCharacter sectCharacterTwoRecord;

    public final SectCharacterMapper sectCharacterMapper;

    public final SectGongfaMapper sectGongfaMapper;

    public final SectGongfaRecordMapper sectGongfaRecordMapper;

    public final MongoTemplate mongoTemplate;

    public GameServiceImpl(SectCharacterMapper sectCharacterMapper,SectGongfaMapper sectGongfaMapper,
                           SectGongfaRecordMapper sectGongfaRecordMapper,MongoTemplate mongoTemplate){
        this.sectCharacterMapper = sectCharacterMapper;
        this.sectGongfaMapper = sectGongfaMapper;
        this.sectGongfaRecordMapper = sectGongfaRecordMapper;
        this.mongoTemplate = mongoTemplate;
    }

    //统计循环回合数
    public static int count;

    //定义返回结果集
    public static Map<String,Object> result = new HashMap<>();

    //命中率
    double hr = RandomUtil.randomDouble(0.75,0.88) ;

    /**
    *@Description:  计算是否血量为0
    *@Parameter:[userGame]
    *@Return:boolean
    *@Author:leiwenlong
    *@Date:2021/7/28
    **/
    @Override
    public boolean die(SectCharacter sectCharacter,String nickName,Map<String, Object> map,String gameter) {
        //gameter 标识宣战方和对战方
        if(ObjectUtil.isNotNull(sectCharacter)){
            //判断血量
            if(sectCharacter.getCharacterHp()>0){
                Integer hp = 0;
                if(gameter.equals("one")){
                    hp = sectCharacterOneRecord.getCharacterHp();
                }else {
                    hp =  sectCharacterTwoRecord.getCharacterHp();
                }
                String msg = nickName+"剩余HP:"+sectCharacter.getCharacterHp()+"/"+hp;
                System.out.println(msg);
                map.put("hp"+gameter+count,msg);
                return true;
             }
        }
        return false;
    }

    /**
    *@Description:  防御计算
    *@Parameter:[userGame]
    *@Return:int
    *@Author:leiwenlong
    *@Date:2021/7/28
    **/
    @Override
    public int defense(SectCharacter sectCharacter) {
        if(ObjectUtil.isNotNull(sectCharacter)){
            //判断能抵挡防御值
            //计算防御概率比数
            BigDecimal bigDecimal = RandomUtil.randomBigDecimal(new BigDecimal(0.66), (new BigDecimal(0.88)));
            BigDecimal decimal = new BigDecimal(sectCharacter.getDefense()).multiply(bigDecimal);
            //生效
            return decimal.intValue();
        }
        return 0;
    }

    /**
    *@Description: 攻击计算
    *@Parameter:[userGame]
    *@Return:int
    *@Author:leiwenlong
    *@Date:2021/7/28
    **/
    @Override
    public int aggressivity(SectCharacter sectCharacter) {
        if(ObjectUtil.isNotNull(sectCharacter)){
            //判断能造成的伤害
            //计算攻击概率比数
            BigDecimal bigDecimal = RandomUtil.randomBigDecimal(new BigDecimal(0.72), (new BigDecimal(1.66)));
            BigDecimal decimal = new BigDecimal(sectCharacter.getAggressivity()).multiply(bigDecimal);
            //生效
            return decimal.intValue();
        }
        return 0;
    }

    /**
    *@Description: 战斗
    *@Parameter:[userGame]
    *@Return:int
    *@Author:leiwenlong
    *@Date:2021/7/28
    **/
    @Override
    public synchronized Map<String,Object> game(UserGame userGame, UserGame userGameTwo) {


        result = new HashMap<>();
        //定义返回结果集
        Map<String,Object> results = new HashMap<>();

        SectUser sectUser = userGame.getSectUser();
        SectUser sectUserTwo = userGameTwo.getSectUser();

        //获取昵称信息
        String nickName = sectUser.getNickName();
        String nickNameTwo = sectUserTwo.getNickName();

        //获取宣战方用户ID
        Integer userId = sectUser.getId();

        //判断今日PK次数是否超10次
        Query query = new Query(Criteria.where("userId").is(userId));
        List<Map> userPkInfoList = mongoTemplate.find(query,Map.class,"pkInfo");

        //判断列表非空
        boolean notNull = ObjectUtil.isNotNull(userPkInfoList);
        if(notNull){
            if(userPkInfoList.size()>=10){
                return results;
            }
        }

        System.out.println("开始进入战斗:"+nickName+"---PK---"+nickNameTwo);

        //宣战方
        SectCharacter sectCharacterOne = sectCharacterMapper.selectById(sectUser.getCharacterId());
        //对战方
        SectCharacter sectCharacterTwo = sectCharacterMapper.selectById(sectUserTwo.getCharacterId());

        //给全局变量赋值
        sectCharacterOneRecord = sectCharacterOne;
        sectCharacterTwoRecord = sectCharacterTwo;

        //获取宣战方功法信息
        List<String> gongfaNameList = sectGongfaRecordMapper.getUserGongfaNameList(sectUser.getId());

        if(gongfaNameList.size()==0){
            gongfaNameList.add("一宿剑舞");
        }

        //获取对战方功法信息
        List<String> gongfaNameListTwo = sectGongfaRecordMapper.getUserGongfaNameList(sectUserTwo.getId());

        if(gongfaNameListTwo.size()==0){
            gongfaNameListTwo.add("千山毒剑");
        }

        Map<String, Object> map = new LinkedHashMap<>();
        //调用PK执行方法
        Map<String, Object> PkMaps = pk(nickName, nickNameTwo, sectCharacterOne, sectCharacterTwo, gongfaNameList, gongfaNameListTwo, map);

        results.put("pkNum",count);
        results.put("pkInfo",PkMaps);

        //解析时区为中国
        Date parse = new Date();
        try {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
        format.setCalendar(new GregorianCalendar(new SimpleTimeZone(0, "GMT")));

            parse = format.parse(format.format(parse));
        } catch (ParseException e) {
            e.printStackTrace();
        }

        PkMaps.put("time",parse);
        PkMaps.put("userId",sectUser.getId());
        mongoTemplate.save(PkMaps,"pkInfo");

        //将循环数值恢复
        count =0;

        return results;
    }

    /**战斗逻辑处理 **/
    private synchronized Map<String, Object> pk(String nickName, String nickNameTwo, SectCharacter sectCharacterOne, SectCharacter sectCharacterTwo,
        List<String> gongfaNameList,List<String> gongfaNameListTwo, Map<String, Object> map
    ) {
        //单独判断
        if(!die(sectCharacterOne,nickName,map,"one") || !die(sectCharacterTwo,nickNameTwo,map,"two")){
            System.out.println("【"+nickName+"】直呼太难了！已身死道消");
            map.put("die"+count,"【"+nickName+"】直呼太难了！已身死道消");
        }

        //从功法列表里随机挑选一门进行对战
        String gongfaName = RandomStr(gongfaNameList.toArray(new String[gongfaNameList.size()]));
        String gongfaNameTwo = RandomStr(gongfaNameListTwo.toArray(new String[gongfaNameListTwo.size()]));

        count++;
        //循环战斗
        while (die(sectCharacterOne,nickName,map,"one") && die(sectCharacterTwo,nickNameTwo,map,"two")){

            //默认设置先手  后续需要调整 根据速度来计算命中率、先后手
            //双方血量
            Integer characterHp = sectCharacterOne.getCharacterHp();
            Integer characterHpTwo = sectCharacterTwo.getCharacterHp();
            System.out.println("#####第"+count+"回合：");//每回合输出回合数

            //判断回合
            if ((count & 1) != 0) { //奇数
               //当回合数为奇数时 由宣战方进攻
                sectCharacterTwo =(SectCharacter) round(sectCharacterOne, sectCharacterTwo, characterHpTwo, nickName, nickNameTwo,gongfaName,map).get("sectCharacter");
                if(sectCharacterTwo.getCharacterHp()<0){
                    return map;
                }else {
                    pk(nickName, nickNameTwo, sectCharacterOne, sectCharacterTwo,gongfaNameList,gongfaNameListTwo,map);
                }
            }else{
                //当回合数为偶数时 由对战方进攻
                sectCharacterOne = (SectCharacter) round(sectCharacterTwo,sectCharacterOne, characterHp,nickNameTwo , nickName,gongfaNameTwo,map).get("sectCharacter");
                if(sectCharacterOne.getCharacterHp()<0){
                    return map;
                }else {
                    pk(nickNameTwo, nickName, sectCharacterTwo, sectCharacterOne,gongfaNameListTwo,gongfaNameList,map);
                }

            }

        }

        return map;
    }

    /** 战斗执行 **/
    private Map<String, Object> round(SectCharacter sectCharacterOne, SectCharacter sectCharacterTwo, Integer characterHpTwo,
              String nickName,String nickNameTwo,String gongfaName,Map<String, Object> map
    ) {
        String msg = "msg" + count;
        String msgTwo = "";

        map.put("pk"+count,"第"+count+"回合：");

        if(mingZhong(hr)==1){
            //调用攻击方法
            int aggressivity = aggressivity(sectCharacterOne);

            //对战方防守
            //实际防御值
            int defense = defense(sectCharacterTwo);

            //如果防御大于攻击 那么此处伤害无效
             if(defense>aggressivity){
                 msgTwo =  "【"+nickNameTwo+"】的防御太强了,抵挡了->>【"+nickName+"】造成的伤害";
                 System.out.println(msgTwo);
                 map.put(msg,msgTwo);
                 map.put("sectCharacter",sectCharacterTwo);
             }else{
                 //计算得出实际扣除血量
                 int actual =  aggressivity - defense;

                 sectCharacterTwo.setCharacterHp(characterHpTwo - actual);

                 //判断是否是暴击伤害
                 if(aggressivity> sectCharacterOne.getAggressivity()){
                     msgTwo = "【"+nickName+"】使用**"+gongfaName+"**对->>【"+nickNameTwo+"】造成了###"+actual+"点暴击伤害";
                     System.out.println(msgTwo);
                     map.put(msg,msgTwo);
                 }else {
                     msgTwo = "【"+nickName+"】使用**"+gongfaName+"**对->>【"+nickNameTwo+"】造成了#"+actual+"点伤害";
                     System.out.println(msgTwo);
                     map.put(msg,msgTwo);
                 }
                 //判断攻击是否大于对方生命值
                 if(actual>sectCharacterTwo.getCharacterHp()){
                     System.out.println("【"+nickNameTwo+"】直呼太难了！已身死道消");
                     map.put("die"+count,"【"+nickNameTwo+"】直呼太难了！已身死道消");
                 }
                 map.put("sectCharacter",sectCharacterTwo);
                 return map;
             }


        }else{
            msgTwo = nickNameTwo+"一个蛇皮走位躲开了技能!";
            System.out.println(msgTwo);
            map.put(msg,msgTwo);
            map.put("sectCharacter",sectCharacterTwo);
        }
        map.put("sectCharacter",sectCharacterTwo);
        return map;
    }

    /** 实现指定命中率的函数 **/
    public static int mingZhong(double hr) {
        Random r = new Random();
        int flag=0;//意味着，不攻击
        //随机产生[0;1],0出现的概率为hr，1出现的概率为1-hr
        int a = r.nextInt(100);//随机产生[0,100)的整数，每个数字出现的概率为1%
        if(a<(int) (hr*100)){ //前hr*100个数字的区间，代表的几率
            flag=1;//意味着攻击
        }else{
            flag=0;
        }
        return flag;
    }

    /** 随机返回字符串数组中的字符串 **/
    public static String RandomStr(String[] strs){
        int random_index = (int) (Math.random()*strs.length);
        return strs[random_index];
    }


}
